package com.example.springbootvuetest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.springbootvuetest.Utils.OrderTask;
import com.example.springbootvuetest.Utils.OrderTaskHandler;
import com.example.springbootvuetest.entity.IdleItem;
import com.example.springbootvuetest.entity.Order;
import com.example.springbootvuetest.entity.User;
import com.example.springbootvuetest.entity.dto.TableDto;
import com.example.springbootvuetest.mapper.IdleItemMapper;
import com.example.springbootvuetest.mapper.OrderMapper;
import com.example.springbootvuetest.service.IIdleItemService;
import com.example.springbootvuetest.service.IOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author shuoye
 * @since 2023-03-14
 */
@Service

public class
OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private IIdleItemService iIdleItemService;

    @Autowired
    private IdleItemMapper idleItemMapper;

    /**
     * 加上事务的排他锁，其他事物不允许读也不允许写，独占资源，另一种共享锁ReadtrantLock
     * 订单的状态 对应0 - 4 orderStatus:['待付款','待发货','待收货','已完成','已取消'],
     * 闲置物品0代表下架，1代表上架，2删除物品
     */
    private static HashMap<Integer, ReentrantLock> lockMap = new HashMap<>();

    static {
        for (int i = 0; i < 100; i++) {
            lockMap.put(i, new ReentrantLock(true));
        }
    }

    /*
     *  用了事务串行化，后续要优化，修改更新的sql，增加更新条件，而不是在代码中判断条件
     *  业务逻辑可优化，改为支付时才下架。
     *  新功能待做，需要新增订单超时处理
     *  （订单超时：
     *  1、重新上架闲置；2、修改订单状态；
     *  3、确保订单取消前不会影响用户的支付，支付前要判断订单状态并加读锁，取消订单时要判断订单状态为未支付才能取消；
     *  4、保证延期任务一定执行，即确保任务不会因为系统异常而消失）
     */
    public boolean addOrder(Order order) {
        IdleItem idleItem2 = iIdleItemService.getById(order.getIdleId());
        System.out.println(idleItem2.getIdleStatus());
        if (idleItem2.getIdleStatus() != 1) {//如果商品已经下架了，失败
            return false;
        }
        IdleItem idleItem = new IdleItem();
        idleItem.setId(order.getIdleId());
        idleItem.setUserId(idleItem2.getUserId());
        idleItem.setIdleStatus((byte) 2);

        int key = order.getIdleId() % 100;
        //从100把锁种拿出一把来加锁
        ReentrantLock lock = lockMap.get(key);
        boolean flag;
        try {
            lock.lock();//加锁
            flag = addOrderHelp(idleItem, order);
        } finally {
            lock.unlock();//解锁
        }
        return flag;
    }

    @Override
    /**
     * 查询用户卖出的闲置
     * @param userId
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<Order> getMySoldIdle(Integer userId) {
        QueryWrapper<IdleItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId).orderByDesc("release_time");
        List<IdleItem> list = idleItemMapper.selectList(queryWrapper);
        List<Order> orderList = null;
        if (list.size() > 0) {
            List<Integer> idleIdList = new ArrayList<>();
            for (IdleItem i : list) {
                idleIdList.add(i.getId());
            }
            orderList = orderMapper.findOrderByIdleIdList(idleIdList);
            Map<Integer, IdleItem> map = new HashMap<>();
            for (IdleItem idle : list) {
                map.put(idle.getId(), idle);
            }
            for (Order o : orderList) {
                o.setIdleItem(map.get(o.getIdleId()));
            }
        }
        return orderList;
    }

    @Override
    /**
     * 获取我的所有订单
     * 同时查询出对应的闲置信息，
     * 未做分页
     * userId建索引
     * @param userId
     * @return
     */
    public List<Order> getMyOrder(Integer userId) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId).orderByDesc("create_time");
        List<Order> list = orderMapper.getMyOrder(userId);
        if (list.size() > 0) {
            List<Integer> idleIdList = new ArrayList<>();
            for (Order i : list) {
                idleIdList.add(i.getIdleId());
            }
            List<IdleItem> idleItemModelList = idleItemMapper.selectBatchIds(idleIdList);
            Map<Integer, IdleItem> map = new HashMap<>();
            for (IdleItem idle : idleItemModelList) {
                map.put(idle.getId(), idle);
            }
            for (Order i : list) {
                i.setIdleItem(map.get(i.getIdleId()));
            }
        }
        return list;
    }

    @Override
    public Order getOrder(Integer id) {
        Order order = orderMapper.selectById(id);
        order.setIdleItem(idleItemMapper.selectById(order.getIdleId()));
        return order;
    }


    /**
     * 新增订单任务处理
     *
     * @param idleItem
     * @param order
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean addOrderHelp(IdleItem idleItem, Order order) {
        IdleItem idleItem2 = iIdleItemService.getById(order.getIdleId());
        if (idleItem2.getIdleStatus() != 1) {
            return false;
        }
        if (iIdleItemService.updateById(idleItem)) {
            if (orderMapper.insert(order) == 1) {
                order.setOrderStatus((byte) 4);
                //半小时未支付则取消订单
                OrderTaskHandler.addOrder(new OrderTask(order, 30 * 60));
                return true;
            } else {
                throw new RuntimeException();
            }
        }
        return false;
    }

    @Override
    public Map<String, Object> getAllOrder(Integer pageNum, Integer pageSize) {
        HashMap<String, Object> resMap = new HashMap<>();
        List<Order> list = orderMapper.getAllOrder((pageNum - 1) * pageSize, pageSize);
        if (list.size() > 0) {
            List<Integer> idleIdList = new ArrayList<>();
            for (Order i : list) {
                idleIdList.add(i.getIdleId());
            }
            List<IdleItem> idleItemList = iIdleItemService.listByIds(idleIdList);
            Map<Integer, IdleItem> map = new HashMap<>();
            for (IdleItem idle : idleItemList) {
                map.put(idle.getId(), idle);
            }
            for (Order i : list) {
                i.setIdleItem(map.get(i.getIdleId()));
            }
        }
        int count = orderMapper.countAllOrder();
        resMap.put("data", list);
        resMap.put("total", count);
        return resMap;
    }

    @Override
    public List<Order> exportOrder() {
        QueryWrapper<Order> queryWrapper = new QueryWrapper<Order>();
        List<Order> list = orderMapper.selectList(queryWrapper);
        if (list.size() > 0) {
            List<Integer> idleIdList = new ArrayList<>();
            for (Order i : list) {
                idleIdList.add(i.getIdleId());
            }
            List<IdleItem> idleItemList = iIdleItemService.listByIds(idleIdList);
            Map<Integer, IdleItem> map = new HashMap<>();
            for (IdleItem idle : idleItemList) {
                map.put(idle.getId(), idle);
            }
            for (Order i : list) {
                i.setIdleItem(map.get(i.getIdleId()));
            }
        }
        return list;
    }

    /**
     * 更新订单
     *
     * @param order
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrder(Order order) {
        //不可修改的信息,mybatisplus 在字段值为空时，在动态SQL语句拼接时不会拼接上去，也就不会更新了
        order.setOrderNumber(null);
        order.setUserId(null);
        order.setIdleId(null);
        order.setCreateTime(null);
        if (order.getOrderStatus() == 4) {
            //取消订单,需要优化，减少数据库查询次数
            Order o = orderMapper.selectById(order.getId());
            if (o.getOrderStatus() != 0) {
                return false;
            }
            IdleItem IdleItem = iIdleItemService.getById(o.getIdleId());
            if (IdleItem.getIdleStatus() == 2) {
                IdleItem idleItem = new IdleItem();
                idleItem.setId(o.getIdleId());
                idleItem.setUserId(idleItem.getUserId());
                idleItem.setIdleStatus((byte) 1);
                if (orderMapper.updateById(order) == 1) {
                    if (iIdleItemService.updateById(idleItem)) {
                        return true;
                    } else {
                        throw new RuntimeException();
                    }
                }
                return false;
            } else {
                if (orderMapper.updateById(order) == 1) {
                    return true;
                } else {
                    throw new RuntimeException();
                }
            }
        }
        return orderMapper.updateById(order) == 1;
    }
}
